package com.echo.im.client.helper;

import cn.hutool.core.collection.CollUtil;
import com.echo.im.common.contant.IMRedisKey;
import com.echo.im.common.model.IMUserInfo;
import com.echo.im.common.enums.IMTerminalType;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 *
 * @author lxy
 * @date 2024-08-14
 */
@Component
@RequiredArgsConstructor
public class OnlineStatusHelper implements OnlineStatus {

    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 输入userIdList，返回Map（serverId，List<IMUserInfo>）
     */
    @Override
    public Map<Integer, List<IMUserInfo>> getServerIdUserInfoMap(List<Long> userIds,Set<Long> offlineUserIds) {
        Map<String, IMUserInfo> sendMap = new HashMap<>();
        for (Integer terminal : IMTerminalType.codes()) {
            userIds.forEach(id -> {
                String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, id.toString(), terminal.toString());
                sendMap.put(key,new IMUserInfo(id, terminal));
            });
        }

        // 批量拉取
        List<Object> serverIds = redisTemplate.opsForValue().multiGet(sendMap.keySet());

        // 格式:map<服务器id,list<接收方>>
        Map<Integer, List<IMUserInfo>> serverMap = new HashMap<>();
        int idx = 0;
        for (Map.Entry<String,IMUserInfo> entry : sendMap.entrySet()) {
            Integer serverId = (Integer)serverIds.get(idx++);
            if (!Objects.isNull(serverId)) {
                List<IMUserInfo> list = serverMap.computeIfAbsent(serverId, o -> new LinkedList<>());
                list.add(entry.getValue());
            }else {
                if (!Objects.isNull(offlineUserIds)){
                    offlineUserIds.add(entry.getValue().getId());
                }
            }
        }

        return serverMap;
    }

    @Override
    public Map<Integer, List<IMUserInfo>> getServerIdUserInfoMap(List<Long> userIds){
        return getServerIdUserInfoMap(userIds,null);
    }

    /**
     * 找寻输入userId 的所有userID的终端在线状况，返回map
     * @param userIds
     * @return
     */
    @Override
    public Map<Long, List<IMTerminalType>> getOnlineTerminal(List<Long> userIds) {
        if(CollUtil.isEmpty(userIds)){
            return Collections.emptyMap();
        }
        // 把所有用户的key都存起来
        Map<String, IMUserInfo> userMap = new HashMap<>();
        for(Long id:userIds){
            for (Integer terminal : IMTerminalType.codes()) {
                String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, id.toString(), terminal.toString());
                userMap.put(key,new IMUserInfo(id,terminal));
            }
        }
        // 批量拉取
        List<Object> serverIds = redisTemplate.opsForValue().multiGet(userMap.keySet());
        // 格式:map<userId,list<设备类型>>
        Map<Long,List<IMTerminalType>> onlineMap = new HashMap<>();
        int idx = 0;
        for (Map.Entry<String,IMUserInfo> entry : userMap.entrySet()) {
            // serverid有值表示用户在线
            if(serverIds.get(idx++) != null){
                IMUserInfo userInfo = entry.getValue();
                List<IMTerminalType> terminals = onlineMap.computeIfAbsent(userInfo.getId(), o -> new LinkedList<>());
                terminals.add(IMTerminalType.fromCode(userInfo.getTerminal()));
            }
        }
        // 去重并返回
        return onlineMap;
    }

    /**
     * 判断用户是否在线
     *
     * @param userId 用户id
     */
    @Override
    public Boolean isUserOnline(Long userId) {
        String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, userId.toString(), "*");
        return !Objects.requireNonNull(redisTemplate.keys(key)).isEmpty();
    }

    /**
     * 得到用户在线列表
     * @param userIds
     * @return
     */
    @Override
    public List<Long> getOnlineUser(List<Long> userIds) {
        return new LinkedList<>(getOnlineTerminal(userIds).keySet());
    }

    /**
     * 获取该用户所有在线终端设备的 serverId 和对应的 terminal 列表
     * @param userId
     * @param terminals
     * @return
     */
    @Override
    public Map<Integer, List<Integer>> getServerIdTerminalListMap(Long userId, List<Integer> terminals) {
        Map<Integer, List<Integer>> serverIdMap = new HashMap<>();

        for (Integer terminal : terminals) {
            String key = createRedisKey(userId, terminal);
            Long serverId = (Long)(redisTemplate.opsForValue().get(key));

            if (serverId != null) {
                // 如果 serverId 不在 map 中，则创建一个新的列表
                serverIdMap.computeIfAbsent(serverId.intValue(), k -> new ArrayList<>()).add(terminal);
            }
        }

        return serverIdMap;
    }

    private String createRedisKey(Long userId, Integer terminal) {
        return String.format("%s:%d:%d", IMRedisKey.IM_USER_SERVER_ID, userId, terminal);
    }
}
